/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package CollaborativeFilttering;

import CollaborativeFilttering.Estruturas.GrafoMusicas;
import CollaborativeFilttering.Estruturas.MusicSet;
import CollaborativeFilttering.Estruturas.ValoresOcorrencia;
import RedeVirtual.Tupla;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Pedro
 */
public class FiltragemColaborativa {

    private GrafoMusicas grafo;
    public ArrayList<MusicSet> musicasNaRede;

    public FiltragemColaborativa() {
        grafo = new GrafoMusicas();
        musicasNaRede = new ArrayList<MusicSet>();
    }

    public void printGrafo() {
        getGrafo().printRede();
        System.out.println(musicasNaRede.size());
    }
    
    public void printMusicasNaRede()
    {
      for(MusicSet ms: musicasNaRede)
            System.out.println(ms.getMusica() + " - " + ms.getOcorrencia());
    }

    public void Filtrar(List<MusicSet> musicas) {
        if (musicas != null) {
            ArrayList<MusicSet> visitadas = new ArrayList<MusicSet>();
            for (MusicSet item : musicas) {
                MusicSet itemTratar;
                if (musicasNaRede.contains(item)) {
                    itemTratar = musicasNaRede.get(musicasNaRede.indexOf(item));
                } else {
                    itemTratar = item;
                    musicasNaRede.add(item);
                }
                
                itemTratar.setOcorrencia(itemTratar.getOcorrencia() + 1);

                for (MusicSet item2 : musicas) {
                    if (!itemTratar.equals(item2) && !visitadas.contains(item2)) {
                        MusicSet itemTratar2;
                        if (musicasNaRede.contains(item2)) {
                            itemTratar2 = musicasNaRede.get(musicasNaRede.indexOf(item2));
                        } else {
                            itemTratar2 = item2;
                            musicasNaRede.add(item2);
                        }
                        Tupla t = new Tupla(itemTratar, itemTratar2);
                        if (this.getGrafo().containsKey(t)) {
                            ValoresOcorrencia valorOcorrencia = this.getGrafo().get(t);
                            valorOcorrencia.setNij(valorOcorrencia.getNij() + 1);
                        } else {
                            this.getGrafo().addEntry(itemTratar, itemTratar2, new ValoresOcorrencia(1));
                        }
                    }
                }
                if (!visitadas.contains(itemTratar)) {
                    visitadas.add(itemTratar);
                }
            }
        }
    }

    public void aplicarCoeficienteDoCosseno() {
        Set<Tupla> tupla = this.grafo.getMap().keySet();

        Tupla[] tuplaarr = new Tupla[tupla.size()];

        Tupla[] toArry = tupla.toArray(tuplaarr);


        for (int i = 0; i < toArry.length; i++) {
            Tupla t = toArry[i];
            ValoresOcorrencia valor = this.grafo.get(t);
            valor.setCoeficienteCosseno(valor.getNij() / (valor.getNij() / Math.sqrt(t.ponto1.getOcorrencia() * t.ponto2.getOcorrencia())));
            if (valor.getCoeficienteCosseno() <= 1) {
                this.getGrafo().getMap().remove(t);
            }
        }
    }

    public GrafoMusicas getGrafo() {
        return grafo;
    }

    public void setGrafo(GrafoMusicas grafo) {
        this.grafo = grafo;
    }

    public void SaveToFile(String path) {
        File arquivo = new File(path);
        try {
            FileWriter wr = new FileWriter(arquivo);

            BufferedWriter buff = new BufferedWriter(wr);

            Set<Tupla> tupla = this.grafo.getMap().keySet();

            Tupla[] tuplaarr = new Tupla[tupla.size()];

            Tupla[] toArry = tupla.toArray(tuplaarr);


            for (int i = 0; i < toArry.length; i++) {
                Tupla t = toArry[i];
                ValoresOcorrencia valor = this.grafo.get(t);
                buff.write(t.ponto1.getMusica() + "@;@" + t.ponto1.getAutor() + "@;@" + t.ponto1.getOcorrencia() + "@!@" + t.ponto2.getMusica() + "@;@" + t.ponto2.getAutor() + "@;@" + t.ponto2.getOcorrencia() + "@!@" + valor.getNij());
                buff.newLine();
            }
            buff.flush();
            buff.close();
            wr.close();
        } catch (Exception e) {
        }

    }

    public void LoadFromFile(String path) {
        File f = new File(path);
        if (f.exists()) {
            try {
                FileReader reader = new FileReader(f);
                BufferedReader leitor = new BufferedReader(reader);
                try {
                    while (leitor.ready()) {
                        String linha = leitor.readLine();
                        String[] dados = linha.split("@!@");

                        String[] music = dados[0].split("@;@");

                        MusicSet musicSet1 = null;
                        if (music.length >= 2) {
                            musicSet1 = new MusicSet(music[0], music[1]);
                        }

                        musicSet1.setOcorrencia(Integer.parseInt(music[2]));

                        music = dados[1].split("@;@");

                        MusicSet musicSet2 = null;
                        if (music.length >= 2) {
                            musicSet2 = new MusicSet(music[0], music[1]);
                        }

                        musicSet2.setOcorrencia(Integer.parseInt(music[2]));

                        if (!musicasNaRede.contains(musicSet1)) {
                            musicasNaRede.add(musicSet1);
                        }

                        if (!musicasNaRede.contains(musicSet2)) {
                            musicasNaRede.add(musicSet2);
                        }

                        Tupla t = new Tupla(musicSet1, musicSet2);
                        this.grafo.addEntry(musicSet1, musicSet2, new ValoresOcorrencia(Double.parseDouble(dados[2])));
                    }
                } catch (IOException ex) {
                    Logger.getLogger(FiltragemColaborativa.class.getName()).log(Level.SEVERE, null, ex);
                }


            } catch (FileNotFoundException ex) {
                Logger.getLogger(FiltragemColaborativa.class.getName()).log(Level.SEVERE, null, ex);
            }


        }
    }

    public double[][] retornaMatrizAdjacencia() {
        ordenaMusicas();
        
        double[][] retorno = new double[this.musicasNaRede.size()][];

        for (int i = 0; i < retorno.length; i++) {
            retorno[i] = new double[retorno.length];
            for (int k = 0; k < retorno[i].length; k++) {
                if (i != k) {
                    retorno[i][k] = 9999;
                } else {
                    retorno[i][k] = 0;
                }
            }
        }

        Set<Tupla> tupla = this.grafo.getMap().keySet();

        Tupla[] tuplaarr = new Tupla[tupla.size()];

        Tupla[] toArry = tupla.toArray(tuplaarr);

        for (int i = 0; i < toArry.length; i++) {
            Tupla t = toArry[i];
            ValoresOcorrencia valor = this.grafo.get(t);
            retorno[musicasNaRede.indexOf(t.ponto1)][musicasNaRede.indexOf(t.ponto2)] =
                    retorno[musicasNaRede.indexOf(t.ponto2)][musicasNaRede.indexOf(t.ponto1)] =
                    valor.getCoeficienteCosseno();
        }
        return retorno;
    }
    
    public void ordenaMusicas()
    {
       ArrayList lista = (ArrayList)musicasNaRede;
       Collections.sort(lista,new Comparator(){
            public int compare(Object o1, Object o2) {
                MusicSet m1 = (MusicSet)o1;
                MusicSet m2 = (MusicSet)o2;
                return (m1.getOcorrencia() < m2.getOcorrencia() ? 1 : (m1.getOcorrencia() > m2.getOcorrencia() ? -1 : 0));
            }
        });
    }

    public ArrayList<MusicSet> getTopSong(int i)
    {
       ArrayList<MusicSet> retorno = new ArrayList<MusicSet>();
       this.ordenaMusicas();
       for(int j = 0; j < i && j < this.musicasNaRede.size(); j++)
       {
           retorno.add(this.musicasNaRede.get(j));
       }
       return retorno;
    }
}
